package shortcircuit.basics;

import shortcircuit.basics.Block;

import java.util.LinkedList;
import java.awt.*;

/**
 * This class contains the display of the falling blocks, and adds onto it the image of the
 * grid of blocks from the Environment. It calculates the speed of the falling blocks and 
 * alters the position of the blocks accordingly, and passes the total pane graphics to Display.
 * @author David Li
 */
public class EnvironmentPane implements Element{
	static final double ACCELERATION = -9.8;
	private Environment _Environment;
	private LinkedList[] fallingBlocks;
	private int[] topBlocks;
	
	/**
	 * Creates an EnvironmentPane, and instantiates a Environment with the passed 
	 * GridDimensions. It also instantiates the LinkedList of falling blocks as
	 * a length of the width of the intended grid.
	 * 
	 * @param theGridDimensions The dimensions of the playing grid
	 * @author David Li
	 */
	public EnvironmentPane(Environment theEnvironment){
		_Environment = theEnvironment;
		Cell[][] theGrid = theEnvironment.getGrid();
		fallingBlocks = new LinkedList[theGrid.length];
		topBlocks = new int[theGrid.length];
		for(int x=0;x<theGrid.length;x++){
			fallingBlocks[x] = new LinkedList();
			for(int y=0;y<theGrid[x].length&&theGrid[x][y].hasBlock();y++)
				topBlocks[x] = y+1;
		}
	}
	
	public int getFallingBlocksSize()
	{
		int length = 0;
		for(int x=0;x<fallingBlocks.length;x++)
		{
			for(int y=0;y<fallingBlocks[x].size();y++)
			{
				length++;
			}
		}
		return length;
	}
	
	/**
	 * Adds a previously-specified block to the top of a previously-specified column
	 * to the falling block arraylist, and sets the original position of the block.
	 * 
	 * @param theBlock The block to be added
	 * @param theColumn The column the block is added to
	 * @author David Li
	 */
	public void addRandomBlock(Block theBlock, int theColumn){
		theBlock.setOrigPosition(new Point(theColumn*Environment.CELLSIZE,0));
		fallingBlocks[theColumn].add(theBlock);
	}
	
	/**
	 * Adds a previously-specified block to a previously specified point, and sets the
	 * original position. Only calls if the block isn't null. Used when the blocks are
	 * falling due to a block being eliminated under them.
	 * 
	 * @param theBlock The block to be added
	 * @param thePoint The point where the block is being added to
	 * @author David Li
	 */
	public void addBlock(Block theBlock, Point thePoint){
		if(theBlock!=null){
			theBlock.reset();
			theBlock.setOrigPosition(new Point(thePoint.x*Environment.CELLSIZE,(_Environment.getGrid()[0].length-thePoint.y)*Environment.CELLSIZE));
			fallingBlocks[thePoint.x].add(theBlock);
		}
	}
	
	/**
	 * Steps forward the environmentpane falling block animation by calling the step
	 * method of each block in turn. Also, if a block touches the topmost block in the grid
	 * by the end of this step, it removes the block from the pane and attaches it to the
	 * environment.
	 * 
	 * @author David Li
	 */
	public int step(){
		Block currentBlock;
		for(int x=0;x<fallingBlocks.length;x++)
			for(int y=0;y<fallingBlocks[x].size();y++){
				currentBlock = (Block)(fallingBlocks[x].get(y));
				currentBlock.step();
				if((currentBlock.getPosition().y>=((_Environment.getGrid()[x].length-1-topBlocks[x])*Environment.CELLSIZE))){
					fallingBlocks[x].remove(currentBlock);
					_Environment.getCell(x,topBlocks[x]).setHoverable(true);
					_Environment.replaceCellContents(_Environment.getCell(x,topBlocks[x]),currentBlock);
					topBlocks[x]++;
				}
			}
		return fallingBlocks[0].size() + fallingBlocks[1].size() + fallingBlocks[2].size() + 
				fallingBlocks[3].size() + fallingBlocks[4].size();
	}
	
	/**
	 * Resets the topBlocks array, so that it properly shows where the topmost blocks of each
	 * column are located.
	 * 
	 * @author David Li
	 */
	public void changeTopBlocks(){
		for(int x=0;x<_Environment.getGrid().length;x++){
			topBlocks[x]=0;
			for(int y=0;y<_Environment.getGrid()[x].length&&_Environment.getGrid()[x][y].hasBlock();y++)
				topBlocks[x]++;
		}

	}
	
	/**
	 * Calls the getGraphics portion of the pane, and calls each sequential environment graphics
	 * and fallingBlocks graphics in turn, with translations.
	 * 
	 * @author David Li
	 */
	public void getGraphics(Graphics g){
		
		g.translate(0, Environment.CELLSIZE * (_Environment.getGrid()[0].length - 1));
		Block currentBlock;
		_Environment.getGraphics(g);
		for(int x=0;x<fallingBlocks.length;x++)
			for(int y=0;y<fallingBlocks[x].size()&&fallingBlocks[x].size()>0;y++){
				currentBlock = (Block)(fallingBlocks[x].get(y));
				Point blockPosition = currentBlock.getPosition();
				//g.translate(blockPosition.x,blockPosition.y+Environment.CELLSIZE);
				currentBlock.getGraphics(g, new Point(blockPosition.x, blockPosition.y + Environment.CELLSIZE));
				//g.translate(-blockPosition.x,-blockPosition.y-Environment.CELLSIZE);
			}
		g.translate(0, -Environment.CELLSIZE * (_Environment.getGrid()[0].length - 1));
	}
	
	/**
	 * Returns the stored environment in this class.
	 * 
	 * @return The stored environment in this class
	 * @author David Li
	 */
	public Environment getEnvironment(){
		return _Environment;
	}
}
